﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Framework.Core.Dependency.Domain;
using log4net;

namespace Framework.Core.Dependency.Visitor
{
    internal class ComExpositionVisitor : IVisitor<Project>
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(ComExpositionVisitor));

        private static readonly Dictionary<string, ComExposition> Cache;

        static ComExpositionVisitor()
        {
            Cache = GetComExposition();
        }

        private static Dictionary<string, ComExposition> GetComExposition()
        {
            Logger.Info("Find Com Exposition by module");
            var comExpositionsByModuleName = new Dictionary<string, ComExposition>();
            var installers = Directory.GetFiles(@"\\parnas32.fr.world.socgen\apps$\CTY_Distribs\RepoDistrib",
                                                "installer.xml",
                                                SearchOption.AllDirectories);

            foreach (var installer in installers)
            {
                var xmlInstaller = XDocument.Load(installer);

                var actions = xmlInstaller.Descendants("Action").ToList();

                foreach (var action in actions)
                {
                    var actionName = action.Attribute("Name").Value;
                    var filters = action.Descendants("Filter").ToList();
                    if (actionName.Equals("COMRegister", StringComparison.CurrentCultureIgnoreCase)
                        && string.IsNullOrWhiteSpace(action.Attribute("Args").Value))
                    {
                        filters.ForEach(x => AddToComExposition(comExpositionsByModuleName, x, ComExposition.Standard));
                    }

                    else if (actionName.Equals("RegAsm", StringComparison.InvariantCultureIgnoreCase))
                    {
                        filters.ForEach(x => AddToComExposition(comExpositionsByModuleName, x, ComExposition.Standard));
                    }

                    else if (actionName.Equals("RegAsmWithCustomTLB", StringComparison.InvariantCultureIgnoreCase))
                    {
                        filters.ForEach(x => AddToComExposition(comExpositionsByModuleName, x, ComExposition.Custom));
                    }
                }
            }
            return comExpositionsByModuleName;
        }

        private static void AddToComExposition(IDictionary<string, ComExposition> comExpositionsByModuleName,
                                               XElement xElement,
                                               ComExposition comExposition)
        {
            if (comExpositionsByModuleName == null)
            {
                throw new ArgumentNullException("comExpositionsByModuleName");
            }
            comExpositionsByModuleName[Path.GetFileNameWithoutExtension(xElement.Attribute("Value").Value)] = comExposition;
        }

        public void Visit(Project item)
        {
            var assemblyName = item.AssemblyName;
            if (Cache.ContainsKey(assemblyName))
            {
                var comExposition = Cache[assemblyName];
                Logger.InfoFormat("Adding ComExposition {0} to module {1}", comExposition, item.AssemblyName);
                item.ComExposition = comExposition;
            }
        }
    }
}